﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WinAPI;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace HookINCS
{
    public enum MouseEventType  
    {
       None,
       MouseDown,
       MouseUp,
       DoubleClick,
       MouseWheel,
       MouseMove
    }
    public enum MouseButton  
    {  
       Left = 0x2,  
       Right = 0x8,  
       Middle = 0x20  
    } 

    public class MouseHook
    {
        
        public event MouseEventHandler MouseDown;
        public event MouseEventHandler MouseUp;
        public event MouseEventHandler MouseMove;
        public event MouseEventHandler MouseWheel;
        //public event EventHandler Click;
        public event MouseEventHandler Click;
        public event EventHandler DoubleClick;  
        private IntPtr hHook;
        public Win32API.HookProc hProc;
        public MouseHook()
        {
        }

        /// <summary>
        /// 添加钩子
        /// </summary>
        /// <returns></returns>
        public int SetHook()
        {
            hProc = new Win32API.HookProc(MouseHookProc);
            hHook = Win32API.SetWindowsHookEx(HookType.WH_MOUSE_LL, hProc, IntPtr.Zero, (uint)0);
            return hHook.ToInt32();
        }
        /// <summary>
        /// 写在钩子
        /// </summary>
        public void UnLock()
        {
            Win32API.UnhookWindowsHookEx(hHook);
        }
        /// <summary>
        /// 钩子响应
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                return (int)Win32API.CallNextHookEx(hHook, nCode, wParam, lParam);
            }
            else
            {
                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
                MouseButtons button = GetButton((int)wParam);
                MouseEventType eventType = GetEventType((int)wParam);
                MouseEventArgs e = new MouseEventArgs(button,(eventType == MouseEventType.DoubleClick ? 2 : 1),  
                        mouseHookStruct.pt.X,mouseHookStruct.pt.Y,  
                        (eventType == MouseEventType.MouseWheel ? (short)((mouseHookStruct.mouseData >> 16) & 0xffff) : 0));
                
                if (button == MouseButtons.Right && mouseHookStruct.flags != 0)
                {
                    eventType = MouseEventType.None;
                }
                switch (eventType)
                {
                    case MouseEventType.MouseDown:  
                         if (MouseDown != null)  
                         {  
                             MouseDown(this, e);  
                         }  
                         break;  
                     case MouseEventType.MouseUp:  
                         if (Click != null)  
                         {  
                             //Click(this, new EventArgs());  
                             Click(this, e);
                         }  
                         if (MouseUp != null)  
                         {  
                             MouseUp(this, e);  
                         }  
                         break;  
                     case MouseEventType.DoubleClick:  
                         if (DoubleClick != null)  
                         {  
                              DoubleClick(this, new EventArgs());  
                          }  
                          break;  
                      case MouseEventType.MouseWheel:  
                          if (MouseWheel != null)  
                          {  
                              MouseWheel(this, e);  
                          }  
                          break;  
                      case MouseEventType.MouseMove:  
                          if (MouseMove != null)  
                          {  
                              MouseMove(this, e);  
                          }  
                          break;  
                      default:  
                          break;  

                }
                return (int)Win32API.CallNextHookEx(hHook, nCode, wParam, lParam);
            }
        }
        private MouseButtons GetButton(Int32 wParam)  
        {  
  
            switch (wParam)  
            {  
  
                case (int)MsgType.WM_LBUTTONDOWN:
                case (int)MsgType.WM_LBUTTONUP:
                case (int)MsgType.WM_LBUTTONDBLCLK:  
                    return MouseButtons.Left;
                case (int)MsgType.WM_RBUTTONDOWN:
                case (int)MsgType.WM_RBUTTONUP:
                case (int)MsgType.WM_RBUTTONDBLCLK:  
                    return MouseButtons.Right;
                case (int)MsgType.WM_MBUTTONDOWN:
                case (int)MsgType.WM_MBUTTONUP:
                case (int)MsgType.WM_MBUTTONDBLCLK:  
                    return MouseButtons.Middle;  
                default:  
                    return MouseButtons.None;  
            }  
        }
        private MouseEventType GetEventType(Int32 wParam)  
        {  
            switch (wParam)  
            {
                case (int)MsgType.WM_LBUTTONDOWN:
                case (int)MsgType.WM_RBUTTONDOWN:
                case (int)MsgType.WM_MBUTTONDOWN:  
                    return MouseEventType.MouseDown;
                case (int)MsgType.WM_LBUTTONUP:
                case (int)MsgType.WM_RBUTTONUP:
                case (int)MsgType.WM_MBUTTONUP:  
                    return MouseEventType.MouseUp;
                case (int)MsgType.WM_LBUTTONDBLCLK:
                case (int)MsgType.WM_RBUTTONDBLCLK:
                case (int)MsgType.WM_MBUTTONDBLCLK:  
                    return MouseEventType.DoubleClick;
                case (int)MsgType.WM_MOUSEWHEEL:  
                    return MouseEventType.MouseWheel;
                case (int)MsgType.WM_MOUSEMOVE:  
                    return MouseEventType.MouseMove;  
                default:  
                    return MouseEventType.None;  
            }  
        } 
    }
}
